接続回路について
DDS基板にあるシリアル入力の(1)STB、(2)DATA、(3)SCKの各端子は、表1に示すようにPIC16F877のREポート側に接続しました。PIC16F877のREポートは、ちょうどポートが3つあるので、ここのポートを選びました。REポートでなければならないという理由は特にありません。
| DDS側のシリアル 入力端子 |
PIC16F877側の 接続ポート |
| STB | RE0 |
| DATA | RE1 |
| SCK | RE2 |
図1に、概略接続図を示します。PICリセット後、確認のため PORTB の LED が1秒間点灯するようにLEDを接続しています。RS232C関連の周辺回路は、RC7,RC6ポートに接続します。詳細はシリアル通信の項目を参照してください。
![]() |
| 図1.DDS制御回路の概略接続図 |
DDS制御プログラム(2)
図2にDDSの制御プログラムのフローチャートを示します。プログラムの解説については、「プログラムの説明(2)」の項をご参照ください。リセット後、PICが動作していることを簡単に確認するため、PORTBに接続されたLEDが1秒間点灯します。DSSの設定ですが、
パソコンから次の4つの設定データをRS232Cでシリアル送信します。
コマンドデータ4ビットと、チップセレクトデータ3ビット分は、次のようにまとめて送ります。
(例)チップセレクト(CS2=「H」、CS1=「H」、CS0=「H」)「111」で、コマンドC「1100」としたとき、
「コマンドデータ」と「チップセレクトデータ」をまとめて、「1100111」とします。すなわち、67Hになります。
次に周波数データは、次のように3つに分割して送ります。
(例)f=10MHzの周波数に設定する場合、16進表記で考えると
10M=10000000→989680H となります。
ここで、80Hが周波数データ(Lower Byte)に相当、96Hが周波数データ(Middle Byte)に相当、98Hが周波数データ(Higher Byte)に相当します。
以上の例から、チップセレクト(CS2=「H」、CS1=「H」、CS0=「H」)に設定されたDDSキットを、f=10MHzの周波数で、コマンドC(DSS
メモリ 1CH に周波数データを書き込み、これを出力する)という場合は、順に67H,80H,96H,98Hの4つのデータを送信します。
シリアル送信されたデータはPIC側で一度バッファに格納された後、DDSへ設定データを送ります。なお、設定完了後も受信動作を続けますので、パソコン側で各種コマンドや周波数を新たに設定することも可能です。



図2.DDS制御プログラムのフローチャート
(注)以下に示すプログラムには、ホームページ画面作成の都合上、空白として全角文字のスペースなどが挿入されています。したがって、下記プログラムリストをそのままコピーしてMPLABのソースファイルとされた場合には、エラーとなることがあります。
→ここをクリックして、下記のプログラムをダウンロードするようにしてください。
ファイル名:「dds_2.asm」 サイズ7.81kバイト
→ここをクリックして、下記のオブジェクトファイルをダウンロードするようにしてください。
ファイル名:「dds_2.hex」 サイズ717バイト
|
;*********************************************************** ; DDSコントロール・プログラム2 ; ;【 動作内容 】 ; PICリセット後、確認のため PORTB の LED が1秒間点灯する。 ; パソコンからチップセレクト・コマンドデータ、及び ; 周波数データを、RS232C シリアル通信で送る。 ; 周波数データは、Lower Byte、Middle Byte、Higher Byte ; の順に、それぞれ 3分割した値を送る。 ; 各データはバッファに一時格納し、データの受信が完了したら、 ; 随時、DDS 設定信号を出力する。 ; ;【 DDS 接続ポート 】 ; (DDS) (PIC) ; STB ………RE0 ; DATA………RE1 ; SCK ………RE2 ; ;【 RS-232C 接続ポート 】 ; 非同期式通信モード ; ボーレート 9600bps ; 8ビット・ノンパリティ ; 割り込みは使用しない ; ;*********************************************************** |
|
|
LIST P=PIC16F877 INCLUDE P16F877.INC |
;(1)プロセッサの種別指定 ;(2)インクルードファイルの指定 |
|
;*********************************************************** ; 変数定義とレジスタ割付 ;*********************************************************** |
|
| COUNT EQU 20H COUNT1 EQU 21H COUNT2 EQU 22H COUNT3 EQU 23H COUNT4 EQU 24H TEMP EQU 25H COUNT_D EQU 26H COUNT_S EQU 27H |
;(3)ループカウンタ ; ループカウンタ1 ; ループカウンタ2 ; ループカウンタ3 ; ループカウンタ4 ; 一時保管データ ; データカウンタ ; シフトカウンタ |
|
;*********************************************************** ; 初期化 ; (注)バンクの位置に注意 ;*********************************************************** |
|
|
ORG 0 BSF STATUS,RP0 MOVLW B'00000010' MOVWF ADCON1 CLRF TRISE CLRF TRISB MOVLW B'10111111' MOVWF TRISC MOVLW B'00100100' MOVWF TXSTA MOVLW 81H MOVWF SPBRG BCF STATUS,RP0 MOVLW B'10010000' MOVWF RCSTA |
;(4)プログラムの開始番地の指定 ;(5)Bank 1 へ切替 ;(6)RE0,RE1,RE2 デジタル入出力 ; ADCON1レジスタの設定 ;(7)PORTE 全ポートを出力に設定 ;(8)PORTB 全ポートを出力に設定 ;(9)RC7/RX(入力),RC6/TX(出力) ;(10)PORTC の設定 ;(11)8BIT,送信許可,非同期,高速 ; TXSTA レジスタの設定 ;(12)ボーレート 9600bps (20MHz:高速設定時) ; SPBRG レジスタの設定 ;(13)Bank 0 へ戻す ;(14)シリアル,8BIT,継続受信許可 ; RCSTA レジスタの設定 |
|
;*********************************************************** ; メインプログラム ;*********************************************************** |
|
MOVLW B'00000111' MOVWF PORTE MAIN BSF STATUS,IRP MOVLW 0A0H MOVWF FSR MOVLW 4H MOVWF COUNT_D |
;(15)DDS信号ラインのレベルの初期設定 ; SCK,DATA,STB = [H],[H],[H] に設定 ; PORTEへ出力(DDSとの通信の初期設定) ;(16)間接アドレス設定 ; バッファの先頭アドレスをセットする ; 間接アドレスポインタの初期化 ;(17)4回繰り返す(DDS設定データ) ; データカウンタのセット |
MOVLW B'11111111' MOVWF PORTB CALL TIME1S MOVLW B'00000000' MOVWF PORTB |
;(18)データ受信待ちになっていることを確認するためのLED表示 ; 11111111 を Wreg にロードする ; PORTBへWregのデータを出力(LEDの点灯) ;(19)1秒のウエイトを入れる ;(20)00000000 を Wreg にロードする ; PORTBへWregのデータを出力(LEDの消灯) |
LPRCV BTFSS PIR1,RCIF GOTO LPRCV |
;(21)USART 受信割り込みフラグビットのチェック ; PIR1 レジスタの RCIF が「0」だったら ; LPRCV ラベル間をループする |
BTFSC RCSTA,FERR GOTO FRAME BTFSC RCSTA,OERR GOTO OVER |
; ****** エラーチェック ****** ;(22)フレーミングエラーのチェック(1:エラー,0:正常) ; フレーミングエラー時 FRAME のラベルへジャンプする ; ;(23)オーバーランエラーのチェック(1:エラー,0:正常) ; オーバーランエラー時 OVER のラベルへジャンプする |
MOVF RCREG,W MOVWF INDF INCF FSR,F DECFSZ COUNT_D,F GOTO LPRCV MOVLW 0 MOVWF INDF |
; ****** 受信データの格納 ****** ;(24)RCREGレジスタから受信データを読み込む ;(25)バッファに格納 ;(26)ポインタ +1 ;(27)データカウンタ −1 ; LPRCV のラベルへ戻り繰り返す ;(28)25,24ビット目のDDS周波数データ(常に0) ; バッファに格納 |
| DDS MOVLW 0A0H MOVWF FSR MOVLW 5H MOVWF COUNT_D |
; ****** 格納データの取りだし ****** ;(29)バッファの先頭アドレスをセットする ; 間接アドレスポインタをリセットする ;(30)5回繰り返す(DDS設定データ) ; データカウンタのセット |
| DDS_SET MOVF INDF,W MOVWF TEMP MOVF COUNT_D,W CALL TABLE MOVWF COUNT_S |
;(31)バッファに格納されているデータをWregにロードする ; 一時保管データへ ;(32)データカウンタの値をWregへロードする(OFFSET) ;(33)シフトカウンタ値の読み込みサブルーチンへ ;(34)シフトカウンタのセット |
| DDS_LP RRF TEMP,F BTFSS STATUS,C GOTO DATA_L GOTO DATA_H |
;(35)DDS設定データを取り出す。 ;(36)データが1だったら次の命令をスキップ ; DATA = [L] ; DATA = [H] |
| SET_SCK BCF PORTE,2 NOP BSF PORTE,2 DECFSZ COUNT_S,F GOTO DDS_LP INCF FSR,F DECFSZ COUNT_D,F GOTO DDS_SET |
;(37)SCK = [L] ;(38)ポートの誤動作防止 ;(39)SCK = [H] ;(40)シフトカウンタ −1 ; DDS_LP のラベルへ戻り繰り返す ;(41)間接アドレスポインタ +1 ;(42)データカウンタ −1 ; DDS_SET のラベルへ戻り繰り返す |
BSF PORTE,1 NOP BCF PORTE,0 NOP BSF PORTE,0 GOTO MAIN |
;(43)DATA = [H] ;(44)ポートの誤動作防止 ;(45)STB = [L] ;(46)ポートの誤動作防止 ;(47)STB = [H] ;(48)繰り返しデータ受信動作に入る |
DATA_L BCF PORTE,1 GOTO SET_SCK DATA_H BSF PORTE,1 GOTO SET_SCK |
;(49)DATA = [L] ;(50)DATA = [H] |
|
;*********************************************************** ; シフトカウンタ・テーブル ;*********************************************************** |
|
| TABLE ADDWF PCL,F NOP DT 2,8,8,8,7 |
;(51)TABLEの定義(PC+OFFSET相当のシフトカウンタ値を持って戻る) ; PC+OFFSET ;(52)ダミーデータ ;(53)各データに対するシフトカウンタ値 |
|
;*********************************************************** ; RS232Cシリアル通信エラー時の処理 ;*********************************************************** |
|
| FRAME MOVLW B'00001111' MOVWF PORTB CALL TIME1S MOVLW B'00000000' MOVWF PORTB MOVF RCREG,W BTFSS RCSTA,OERR GOTO MAIN |
; <フレーミングエラー時の処理> ;(54)00001111 を Wreg にロードする ; PORTBへWregのデータを出力(LEDの点灯状態でエラーを知らせる) ;(55)1秒のウエイトを入れる ;(56)00000000 を Wreg にロードする ; PORTBへWregのデータを出力(LEDの消灯) ;(57)ダミーの入力とFERRフラグをリセット(RCREGをリードするとクリア) ;(58)オーバーランエラーのチェック(1:エラー,0:正常) ; オーバーランエラーがなければ MAIN のラベルへジャンプする |
OVER MOVLW B'11110000' MOVWF PORTB CALL TIME1S MOVLW B'00000000' MOVWF PORTB BCF RCSTA,CREN BSF RCSTA,CREN GOTO MAIN |
; <オーバーランエラー時の処理> ;(59)11110000 を Wreg にロードする ; PORTBへWregのデータを出力(LEDの点灯状態でエラーを知らせる) ;(60)1秒のウエイトを入れる ;(61)00000000 を Wreg にロードする ; PORTBへWregのデータを出力(LEDの消灯) ;(62)OERRのリセット(ビットCREN のクリアによりクリアする) ;(63)連続受信を許可する ;(64)MAIN のラベルへジャンプする |
| ;*********************************************************** ;遅延サブルーチン ;*********************************************************** ;100μs遅延サブルーチン(20MHzクロック時) ;・・・・・別記プログラムリスト参照・・・・・ ; ;10ms遅延サブルーチン(20MHzクロック時) ;・・・・・別記プログラムリスト参照・・・・・ ; ;1s遅延サブルーチン(20MHzクロック時) ;・・・・・別記プログラムリスト参照・・・・・ |
|
END |
|
【プログラムの説明(2)】![]()
このプログラムについて、順を追って解説を加えておきましょう。
(1)プロセッサの種別指定
定義の仕方は「PROCESSOR」か「LIST」命令を使って設定します。ここで指定するプロセッサ名称は、パッケージの種類を示すサフィックス(最後の英記号の部分)は不要です。
PROCESSOR PIC16F877
または
LIST P=PIC16F877
(2)標準ヘッダーファイルのインクルード
標準ヘッダーファイルとは、各プロセッサが持っているSFR(Special Function Register)をラベル(記号)で使える
ため、ラベルとハードウェアの場所とを定義しているファイルです。標準ヘッダーファイルは 「プロセッサ名.INC」というファイル名で統一されて、MPLABのディレクトリに格納されています。従って、これのインクルード方法は下記のようにして行います。
一度、参考までに標準ヘッダーファイルの内容をエディタ等で見ておくことをお勧めします。
INCLUDE P16F877.INC
または
#INCLUDE P16F877.INC
(3)変数定義とレジスタ割付
レジスタファイルアドレスを指定するときに、アドレス数値を直接指定することもできますが、数値だけでは間違いも多く、プログラム自身も分かりにくくなってしまいます。そこで、EQU命令などを使ってラベルを設定し変数を定義します。レジスタファイルアドレスは、7ビットあるので、00〜7Fまで最大128個のレジスタが指定できますが、実際に物理的に実装されて汎用的に使用できるレジスタ数はデバイスによって異なっていますので注意が必要です。
PIC16F877の汎用レジスタのアドレスは、20H〜7FH
となっていますので、20H以降のアドレスに割り付けます。
(4)プログラムの開始番地の指定
「ORG」はプログラムの開始番地を指定する擬似命令で、ORG以下の実際のプログラム命令が格納されるプログラムメモリ内の位置(アドレス)を指定します。
ORG 0 ;0番地から格納することを示します。
コンピュータは一般に電源投入時やリセットをすると必ず0番地からスタートするようになっているので、0番地には必ず命令があることが必要です。
(5)Bank 1 へ切替
PICには各種の動作モードを設定するための Special
Register と呼ばれるものが用意されています。PICを動作させるためには、まずこのSpecial
Registerの設定から始めます。そしてそれらは全て、Register
File と呼ぶメモリとして用意されています。その
Register Fileは Bank0, Bank1, Bank2, Bank3
とよばれるアドレス空間をもっているため、多少アクセスの仕方が面倒です。つまりRESET後の通常はBank0となっているので、Bank1側のレジスタにアクセスするときはBankの切替えをしてからとなります。またBank0とBank1に同じ物があるときにはどちらでも同じ様に使えます。
Bank1へ切り替える方法ですが、「STATUS」レジスタにある2ビットのRP0、RP1を変えてBankを指定します。デフォルトは、Bank0です。表2にBankとRP1,RP0ビットとの関係を示します。Bank1へ切り替えるためには、RP0ビットを「1」にします。(RP1はデフォルトで「0」なので変える必要はない。)
BSF STATUS,RP0
「STATUS」レジスタのRP0ビットを「1」にする。
| Bank | RP1 | RP0 |
| 0 | 0 | 0 |
| 1 | 0 | 1 |
| 2 | 1 | 0 |
| 3 | 1 | 1 |
(6)RE0,RE1,RE2 デジタル入出力
ADCON1レジスタの設定
![]()
REポートをディジタル入出力ポートとして使用するためには、ADCON1レジスタの設定が必要
REポートをディジタル入出力ポートとして使用するためには、ADCON1レジスタの設定が必要になります。PICのリセット後は、REポートがA/D変換の入力ポートになっているからです。(RAポートも同様)ADCON1レジスタの3〜0ビット(PCFGx)の設定内容より決定します。PCFGx=「0010」
or 「0011」 or 「0100」 or 「0101」 or 「0110」 or 「0111」 or 「1100」
or 「1101」 or 「1110」 or 「1111」のいずれかのときREポートはディジタル入出力ポートになることが分かります。(このとき、RAポートは使用しないので、RAポートの設定は無関係とします)
ADCON1レジスタの設定内容の詳細は、こちらをご覧ください。→ADCON1レジスタの設定内容について
なお、ADCON1レジスタの7〜4ビットは、簡単のためとりあえず「0」とでもしておき、またPCFGx=「0010」とすることで、すなわち、「ADCON1→B’00000010’ (2H)」に設定することで、REポートをディジタル入出力ポートとして使用することができます。
(7)PORTE 全ポートを出力に設定
TRISEレジスタを、CLRF(fレジスタをゼロクリアする命令)で出力設定とします。
CLRF TRISE
「TRISEレジスタをゼロクリアする。すなわち、PORTE全ポートを出力に設定する」
(8)PORTB 全ポートを出力に設定
TRISBレジスタを、CLRF(fレジスタをゼロクリアする命令)で出力設定とします。
CLRF TRISB
「TRISBレジスタをゼロクリアする。すなわち、PORTB全ポートを出力に設定する」
PORTBにはLEDが接続されており、DDSへシリアル入力する状態に入ったときの確認のために、点灯するようにしています。
(9)RC7/RX(入力),RC6/TX(出力)
シリアル通信の入出力ポートとして、受信入力ポート(RC7/RX)と、送信出力ポート(RC6/TX)を使います。他のRCポートは使いませんので、とりあえず入力に設定しておきます。したがって、RC6のみ出力設定にします。
ということで、B’10111111’ (BFH)をWregにロードする。
(10)PORTC の設定
Wregの内容をTRISCレジスタに上書きする。
(11)8BIT,送信許可,非同期,高速,TXSTA レジスタの設定
「シリアル通信機能」の制御用レジスタの解説項目でTXSTAレジスタを参照してください。
TXSTAレジスタの内容
ということで、TXSTA→B’00100100’ (24H)
(12)ボーレート 9600bps (20MHz:高速設定時), SPBRG レジスタの設定
「シリアル通信機能」のSPBREGレジスタの解説項目で表3.SPBRGの設定値とボーレートを参照してください。ボーレートを9600bpsに設定します。表3−1の低速モードや、表3−2の高速モードがありますが、ここでは高速モードの9600bpsを選択します。クロック周波数が20MHzの場合は、低速モードより高速モードの方がエラーレートが小さいためです。したがって、高速モードの場合のSPBREGは、81Hに設定すればよいことが分かります。
(注)MicroChip社のデータシートは、SPBREGの設定表示は10進数(decimal)になっていますので注意してください。
(13)Bank 0 へ戻す
Bank1での設定が終了した後は、Bank0に戻しておきます。Bank1へ切り替えるためには、RP0ビットを「0」にします。(RP1はデフォルトで「0」なので変える必要はない。)
BCF STATUS,RP0
「STATUS」レジスタのRP0ビットを「0」にする。すなわち、Bank0に戻す。」
(14)シリアル,8BIT,継続受信許可,RCSTA レジスタの設定
「シリアル通信機能」の制御用レジスタの解説項目でRCSTAレジスタを参照してください。
RCSTAレジスタの内容の決定
ということで、RCSTA→B’10010000’ (90H)
(15)DDS信号ラインのレベルの初期設定
SCK,DATA,STB = [H],[H],[H] に設定,PORTEへ出力(DDSとの通信の初期設定)
DDSとのシリアル通信を行う前に、信号ライン(SCK,DATA,STB)をすべて「H」に初期設定しておきます。
(16)間接アドレス設定 ![]()
バッファの先頭アドレスをセット 間接アドレスポインタの初期化
データメモリのアクセス方法に、直接レジスタのアドレスを指定してアクセスする直接アドレッシングのほかに、間接アドレッシングという方法があります。間接アドレッシングは、FSRレジスタ(File
Selection Register)と、STATUSレジスタ中のIRPビットを使います。このFSRレジスタがプログラム中で自由に書き換えられるので、プログラム中にバッファなどを作って連続した領域を順にアクセスするのに便利に使えます。また、間接アドレッシングで指定されたデータメモリは、INDFレジスタを経由して間接的にアクセスします。すなわち、指定したデータメモリに書き込む場合には、INDFレジスタに書き込み、指定したデータメモリの内容を読み出すときには、INDFレジスタの内容を読み込みます。
図3に間接アドレッシングでのデータメモリ・アドレス指定についての解説図を示します。
![]() |
| 図3.間接アドレッシングのデータメモリ・アドレス指定について |
(プログラム例)Bank3の汎用データメモリのアドレス20Hを指定したいとき
STATUSレジスタのRP0,RP1を使ってBankの切り替えをする必要はありません、次のように直接任意のBankをアクセスします。図2のBank指定から、STATUSレジスタのIRPを「1」、FSRレジスタの7ビット目を「1」にします。
また、場所アドレスの指定からFSRレジスタの6〜0ビット目を、20Hにしますが、7ビット目が「1」になっていますので、FSRレジスタは、A0Hにします。したがって、
BSF STATUS,IRP ;STATUSレジスタのIRPビットを「1」にする。
MOVLW 0A0H ;A0HをWregレジスタにロードする
MOVWF FSR ;Wregレジスタの内容をFSRレジスタに格納する。
となります。
(17)4回繰り返す(DDS設定データ),データカウンタのセット
パソコンから RS232C シリアル通信にて、次の1〜4までの各データが順に送られてくるので、受信動作を4回繰り返すようにデータカウンタをセットします。
(18)データ受信待ちになっていることを確認するためのLED表示
11111111 を Wreg にロードし、PORTBへWregのデータを出力(LEDの全点灯)
ここで、レジスタの初期設定が終了し、パソコンからのデータ入力待ち(受信状態)に入ったことを確認するため、
PORTB の LED を全点灯させるようにします。
(19)1秒のウエイトを入れる
PORTB の LED の点灯時間を1秒間に設定します。ここでは、遅延サブルーチンを使っています。
(20)00000000 を Wreg にロードし、
PORTBへWregのデータを出力(LEDの消灯)
点灯していたLEDを消灯させ、データの受信状態に入ります。
(21)USART 受信割り込みフラグビットのチェック(1:USART 受信バッファがフル,
0:空)
受信バッファが空であれば LPRCV のラベル間を繰り返す
周辺機能の割り込みのフラグビットが割り当てられているPIR1レジスタのUSART
受信割り込みフラグビット(RCIF)の状態をチェックします。
USART受信バッファがフルであるとすると、RCIFが「1」となり、次の命令で分岐されます。
BTFSS PIR1,RCIF
「PIR1」レジスタのRCIFビットが「1」だったら次の命令をスキップし、ループから抜けます。
GOTO LPRCV
ただし、受信バッファが空の間は、「PIR1」レジスタのRCIFビットが「0」のままですので、LPRCVラベルへ戻ってループを繰り返します。
(22)フレーミングエラーのチェック(1:エラー,0:正常)
受信ステータスおよびコントロールレジスタであるRCSTAレジスタのフレーミングエラービット(FERR)の状態をチェックします。
BTFSC RCSTA,FERR
「RCSTA」レジスタのFERRビットが正常の「0」だったら次の命令をスキップし、オーバーランエラーのチェックへ進みます。
GOTO FRAME
フレーミングエラー時 FRAME のラベルへジャンプします。
(23)オーバーランエラーのチェック(1:エラー,0:正常)
受信ステータスおよびコントロールレジスタであるRCSTAレジスタのオーバーランエラービット(OERR)の状態をチェックします。
BTFSC RCSTA,OERR
「RCSTA」レジスタのOERRビットが正常の「0」だったら次の命令をスキップし、受信データの格納へ進みます。
GOTO OVER
オーバーランエラー時 OVERのラベルへジャンプします。
(24)RCREGレジスタから受信データを読み込む
RCREGレジスタ(受信データが格納されている)内容をWregへロードする。
(25)バッファに格納
データメモリに書き込む場合には、INDFレジスタを経由して間接的に書き込みます。
MOVWF INDF
INDFレジスタにWregの内容を格納(→間接アドレッシングで指定したデータメモリに格納される)
(26)ポインタ +1
バッファの間接アドレスポインタを+1にして、次のアドレスを指定します。
(27)データカウンタ −1, LPRCV のラベルへ戻り繰り返す
パソコンから RS232C シリアル通信にて、4Byte分のデータが順に送られてくるので、(17)で4回繰り返すようにセットされたデータカウンタを−1ずつ減らし、0になるまでLPRCV間の受信動作を繰り返します。
(28)24,25ビット目のDDS周波数データ(常に0),バッファに格納
これまでパソコンからは RS232C シリアル通信にて、チップセレクト&コマンドデータ、0ビット目〜23ビット目までの周波数データ(下記に示す1〜4までのデータ)がバッファに格納されました。DDSの周波数データは0ビット〜25ビットで構成されているため、ここで24,25ビット目のDDS周波数データもバッファに格納します。ただし、DDSの設定仕様から24,25ビット目のデータについては、常に0ですので、あえてシリアル通信でこの部分のデータを送る必要はありません。
(29)バッファの先頭アドレスをセットする,間接アドレスポインタをリセットする
データの取り出しルーチンに入ったとき、格納されているバッファの先頭に間接アドレスポインタをセットします。
STATUSレジスタのIRPは「1」のまま変化していませんので、あえてセットする必要はありません。FSRの設定を(16)の項目と同じA0Hにセットします。
(30)5回繰り返す(DDS設定データ),データカウンタのセット
(28)でバッファに書き込まれた1〜5までの5つのデータを取り出すため、動作を5回繰り返すようにデータカウンタをセットします。
(31)バッファに格納されているデータをWregにロードする,一時保管データへ
バッファに書き込まれたデータを読み込む場合には、INDFレジスタを経由して間接的に読み込みます。読み込まれたデータは、TEMPレジスタに一時保管しておきます。
(32)データカウンタの値をWregへロードする(OFFSET)
テーブルに記載されているシフトカウンタ値を読み込んでくるため、データカウンタの値をWregにロードします。このデータカウンタの値は、プログラムカウンタにデータカウンタの値(OFFSET分)を足し合わせることで、シフトカウンタ値が記載されたテーブルの位置関係を指し示すようになっています。
(33)シフトカウンタ値の読み込みサブルーチンへ
シフトカウンタ値を読み込むサブルーチンへ飛びます。
(34)シフトカウンタのセット
読み込まれたシフトカウンタの値をセットします。
(35)DDS設定データを取り出す
TEMPレジスタに一時保管されたDDS設定データの内容を、1ビットキャリを含めて右に移動させ、その結果をTEMPレジスタに上書きします。このときTEMPレジスタのLSBのビット(0
or 1)によってCフラグが変化しますので、次の条件分岐で下位から1ビット分ずつDDSの設定データを取り出すことができます。
(36)データが1だったら次の命令をスキップ
DATA = [L] か DATA = [H] かの条件分岐
1ビット分の読み込まれたデータが、1だったらDDSへのDATA信号ラインを[H]に、0だったらDDSへのDATA信号ラインを[L]にする条件分岐になります。
(37)SCK = [L]
DDSへのSCK信号ラインを[L]にします。
(38)ポートの誤動作防止
![]()
BSF,BCFなどのビット操作命令で、同じポートに出力する場合には、間にダミーとしてNOP命令などを入れる
ここは、(37)と(39)のように、BSF,BCFなどのビット操作命令により同一ポートを続けて設定していると、ポートが誤動作をすることがあるので、ダミーとしてNOPを入れています。BSF,BCFなどのビット操作命令は、一度ポートレジスタのすべてのビットの状態を読み込み、指定ビットのみを変更して再度ポートレジスタに上書きするという操作がされます。すなわち、最初の命令(37)の出力がなされ、次の命令(39)が出力される前に、一度入力動作があるのです。最初の命令の出力と次の命令の入力動作の間は、1クロック分しかなく、20MHzクロックの場合にはわずかに50nsecです。出力ピンの負荷に何らかの容量成分があると、信号の立ち上がりや立ち下がりが遅れるため、最初の命令の出力が完全に落ち着く前に次の命令で読み込みを実行してしまうため誤動作が発生しやすくなります。この対策としては、ビット操作命令で連続して同じポートに出力する場合には、間にNOP命令など他の命令を最低1個挿入するようにします。
(39)SCK = [H]
DDSへのSCK信号ラインを[H]にします。このとき、SCKの立ち上がりでDATAが読み込まれます。
(40)シフトカウンタ −1,DDS_LP のラベルへ戻り繰り返す
シフトカウンタの値を1ずつ減らし、0になるまでDDS_LPとあるラベルへ戻り、DATAの読み込み動作を繰り返します。
(41)間接アドレスポインタ +1
バッファの間接アドレスポインタを+1にして、次のアドレスを指定します。
(42)データカウンタ −1,DDS_SET のラベルへ戻り繰り返す
データカウンタの値を1ずつ減らし、0になるまでDDS_SETとあるラベルへ戻り、DATAの読み込み動作を繰り返します。
(43)DATA = [H]
すべてのDATAがDDSへ送り終えたら、DATA信号ラインを「H」に設定しておきます。
(44)ポートの誤動作防止
ここは、(43)と(45)のように、BSF,BCFなどのビット操作命令を使って、同じポートに出力する場合には、間にダミーとしてNOP命令などを入れる。(38)参照
(45)STB = [L]
DDSへのSTB信号ラインを[L]にします。このとき、STBの立ち下がりで、読み込まれたコマンド・データが実行され、DDSの出力端子から10MHzの信号が出力されます。
(46)ポートの誤動作防止
ここは、(45)と(47)のように、BSF,BCFなどのビット操作命令を使って、同じポートに出力する場合には、間にダミーとしてNOP命令などを入れる。(38)参照
(47)STB = [H]
STB信号ラインを「H」に設定して終了します。
(48)繰り返しデータ受信動作に入る
DDSの設定が終了した後、PIC側の動作としては、次の新たな設定データが受信されるのを待ちます。
(49)DATA = [L]
(36)の分岐命令で、1ビット分の読み込まれたデータが、0だったらDDSへのDATA信号ラインを[L]にするルーチン。
(50)DATA = [H]
(36)の分岐命令で、1ビット分の読み込まれたデータが、1だったらDDSへのDATA信号ラインを[H]にするルーチン。
(51)TABLEの定義(PC+OFFSET相当のシフトカウンタ値を持って戻る)
PC+OFFSET
データテーブルのサブルーチンに来ると、プログラムカウンタに、Wregの値(オフセット)が加算されます。その加算結果をプログラムカウンタとしますので、そのデータカウンタ(アドレス)で指定された値を示すようになります。
ADDWF PCL,F ;プログラムカウンタに、Wregの値(オフセット)を加算し、
その加算結果をプログラムカウンタする。
(52)ダミーデータ
データカウンタの値は、シフトカウンタ値が記載されたテーブルの位置関係を指し示します。データカウンタ(アドレス)で指定された値の位置関係を対応させるために、ここにダミーを入れておきます。
(注)(42)の分岐命令により、データカウンタが0のときデータの読み込みルーチンを抜けてしまうため、ここのアドレス位置にデータを記載しても読み込みがされませんのでNOPとしています。
(53)各データに対するシフトカウンタ値
表3に各DDS設定データに対するシフトカウンタ値を示します。
まずチップセレクト&コマンドデータですが、チップセレクト端子は、CS2、CS1、CS0の3ビットで構成され、コマンドデータは、4ビットですので、合計で7ビット分になります。次に周波数データですが、Lower
Byteは 0ビット目〜7ビット目までの8ビット分、Middle Byteは 8ビット目〜15ビット目までの8ビット分、Higher
Byteは 16ビット目〜23ビット目までの8ビット分、さらに、24,25ビット目で2ビット分というように、シフトカウンタ値を設定します。
| データの項目 | シフトカウンタ値 |
| チップセレクト&コマンドデータ | 7 |
| 周波数データ(Lower Byte: 0ビット目〜7ビット目) | 8 |
| 周波数データ(Middle Byte: 8ビット目〜15ビット目) | 8 |
| 周波数データ(Higher Byte: 16ビット目〜23ビット目) | 8 |
| 周波数データ(24,25ビット目 ビットの値は常に0) | 2 |
(54)<フレーミングエラー時の処理>
00001111 を Wreg にロードする,PORTBへWregのデータを出力
(LEDの点灯状態でエラーを知らせる)
ここでは、フレーミングエラーが発生したことを確認するため、 PORTB 下位4ビットの
LED を点灯させるようにします。
(55)1秒のウエイトを入れる
PORTB の LED の点灯時間を1秒間に設定します。ここでは、遅延サブルーチンを使っています。
(56)00000000 を Wreg にロードし、
PORTBへWregのデータを出力(LEDの消灯)
点灯していたLEDを消灯させます。
(57)ダミーの入力(RCREGをリードするとFERRがクリアされる)![]()
<フレーミングエラー時の処理>
受信時にフレーミングエラーが発生した場合、フレーミングエラービットFREEが「1」となっています。
フレーミングエラービットをリセットする場合には、RCREGレジスタ(USART受信レジスタ)をWregにロードするというダミー命令を実行します。
(58)オーバーランエラーのチェック(1:エラー,0:正常)
オーバーランエラーがなければ MAIN のラベルへジャンプする
受信ステータスおよびコントロールレジスタであるRCSTAレジスタのオーバーランエラービット(OERR)の状態をチェックします。
BTFSS RCSTA,OERR
「RCSTA」レジスタのOERRビットがエラーの「1」だったら次の命令をスキップし、オーバーランエラーのチェックへ進みます。
GOTO MAIN
オーバーランエラーがなければMAINのラベルへジャンプし、受信を最初からやり直します。
(59)<オーバーランエラー時の処理>
11110000 を Wreg にロードする,PORTBへWregのデータを出力
(LEDの点灯状態でエラーを知らせる)
ここでは、オーバーランエラーが発生したことを確認するため、 PORTB 上位4ビットの
LED を点灯させるようにします。
(60)1秒のウエイトを入れる
PORTB の LED の点灯時間を1秒間に設定します。ここでは、遅延サブルーチンを使っています。
(61)00000000 を Wreg にロードし、
PORTBへWregのデータを出力(LEDの消灯)
点灯していたLEDを消灯させます。
(62)OERRのリセット(ビットCREN のクリアによりクリアする)![]()
<オーバーランエラー時の処理>
受信時にオーバーランエラーが発生した場合、オーバーランエラービットOERRが「1」となっています。
オーバーランエラービットをリセットする場合には、RCSTAレジスタ(受信ステータスおよびコントロールレジスタ)の連続受信イネーブルビット(CREN)をクリアすることにより、オーバーランエラービット(OERR)がクリアされます。
(63)連続受信を許可する
先のオーバーランエラー時の処理で連続受信イネーブルビット(CREN)がクリアされてしまっているので、元の「1」にセットして戻しておきます。
(64)MAIN のラベルへジャンプする
MAINのラベルへジャンプし、受信を最初からやり直します。
DDSの動作確認
それでは、パソコンからシリアル通信ソフト「Acknowrich」を使って、DDSをコントロールしてみましょう。Acknowrichからのデータ転送は、バイナリモードで行います。
図4は、Acknowrichを使ったDDSの設定データを示しています。そのときのDDSの出力波形(図5)をオシロスコープで見たところです。3画像とも比較のため、タイムレンジは同じにしています。これらの結果から、パソコンからDDSを制御できることが確認できました。
![]() |
![]() |
![]() |
| (1)コマンドC f=1MHz設定 |
(2)コマンドC f=2MHz設定 |
(3)コマンドC f=10MHz設定 |
| 図4.Acknowrichを使ったDDSの設定 | ||
![]() |
![]() |
![]() |
| (1)f=1MHz設定 | (2)f=2MHz設定 | (3)f=10MHz設定 |
| 図4.DDSの出力波形 | ||
このようにして、パソコンからDDSキットを制御できることがわかりました。しかし、シリアル通信ソフト「Acknowrich」からDDSの設定データを入力するのは何かと不便です。そこで、「次へ」は専用のDDS制御ソフトをVisualBasicで開発していくことにします。
![]() |
|
![]() |
|